//*****************************************
//	Oscar Rodriguez Polo	c) 2004
//
//	 PackMemManager.h
//
//	PACK MEMORY Manager 
//  THE LIMIT OF THIS MEMORY MANAGER IS 16 MBytes
//
//*****************************************

 

#ifndef _PACK_MEM_MANAGER_H
#define _PACK_MEM_MANAGER_H

//!Only can be included if first it is included the LowLevel



#include <public/basic_types.h>

//!Declare PackPool 
class PackPool;
//!Declare PackListHandler 
class CPackListHandler;

extern PackPool globalPackListPool;


/*!
 * \class  CPackHandler  PackMemManager.h " PackMemManager.h"
 * \author Oscar Rodriguez Polo
 * \brief class that implements the Nanosat1B Package Handler
*/
class CPackHandler{

        //!PackIndex, it is replicates three times for bit correction
        word16_t PackIndex0,PackIndex1, PackIndex2;


		friend class  PackPool;
		friend class  CPackListHandler;



        //*********************************************************************
    	//@{ Pack Index Control
        
        /**
         * \brief Set the packet indexes
		 * \param packIndex0 packet Index 0
         * \param packIndex1 packet Index 1
         * \param packIndex2 packet Index 2
         */
            
        inline void  SetIndex(word16_t packIndex0
        										, word16_t packIndex1
        										, word16_t packIndex2);

		/**
         * \brief Get the packet indexes
		 * \param rPackIndex0 packet Index 0
         * \param rPackIndex1 packet Index 1
         * \param rPackIndex2 packet Index 2
         */
    
        inline void  GetIndex(word16_t & rPackIndex0
        										, word16_t & rPackIndex1
        										, word16_t &rPackIndex2);

public:

        //!Constructor, Init as not Valid Pack
        CPackHandler();


		/**
         * \brief Check if packet index is in the interval [firstPack lastPack]
		 * \param firstPack
         * \param lastPack
         * \return true if packet index is in the interval
         */

		bool_t  IsIndexInInterval(word16_t firstPack
												, word16_t lastPack);

		//@}
        
		//*********************************************************************
    	//@{ Word16 Access Control
               
        /**
         * \brief Read a word16 from the package 
		 * \param wordIndex word Index  
         * \param rwordValue reference where the word16 is copied  
         * \return false if it is not a valid package
         */
                
        bool_t  ReadWord16(uint8_t wordIndex
        									, word16_t & rwordValue) ;
        
                
        /**
         * \brief Write a word16 in the package 
		 * \param wordIndex word Index 
         * \param wordValue Word16 value 
         * \return false if it is not a valid package
         */
        
        bool_t  WriteWord16(uint8_t wordIndex
        											, word16_t wordValue);
              
        
        /**
         * \brief Read an array of Word16 from the package, only read the  
         * 	      words which are in the package
		 * \param firstWordIndex Index of the first word to read   
         * \param wordsArray array of word16 where data are copied
         * \param wordsNumber number of word16 to read
         * \return false if it is not a valid package
         */
        
        bool_t ReadWord16Num(uint8_t firstWordIndex
        									, word16_t * wordsArray
        									, uint8_t wordsCounter) ;

        /**
         * \brief Write a number of Word16  in the package, only write the  
         * 	      words if there is espace in the package
		 * \param firstWordIndex Index of the first word to write   
         * \param wordsArray array of word16 to write 
         * \param wordsNumber number of word16 to write
         * \return false if it is not a valid package
         */
            
        bool_t WriteWord16Num(uint8_t firstWordIndex
        									, const word16_t * wordsArray
        									, uint8_t wordsCounter);


		//@}

		//*********************************************************************
    	//@{ Byte Access Control, distinguish between Little and Big endian 

        
        /**
         * \brief Read a byte from the package 
		 * \param byteIndex byte Index  
         * \param rbyteValue reference where the byte is copied  
         * \return false if it is not a valid package
         */
        
        bool_t ReadByte(byte_t byteIndex
        										, byte_t &rbyteValue);
        
        /**
         * \brief Write a byte in the package 
		 * \param byteIndex byte Index 
         * \param byteValue byte value 
         * \return false if it is not a valid package
         */
        
        bool_t WriteByte(byte_t byteIndex, byte_t byteValue);

		//@}
        
        //*******************************************************
		//@{ Check and CRC

        /**
         * \brief Check if it is a valid package 
		 * \return false if it is not a valid package
         */
        
        bool_t IsValid() ;
		
       
        /*!
        *  \brief Check CRC with a number of bytes of the package
        *  The check is Ok if the next 2 bytes are equal than the calculated CRC
        *  This method cannot handle the pack as a byte array, it must call   
        *  ReadByte and ReadWord16
        *  \param firtByteIndex firt Byte to Calculate the CRC
        *  \param numBytes of the CRC checking 
        *  
        * \return true if CRC check of the packet is OK and false if not
        */

        bool_t CheckCRC(byte_t firtByteIndex, byte_t numBytes);

        
        /*!
        *  Calculate CRC and return it 
        *  \param firtByteIndex firt Byte to Calculate the CRC
        *  \param numBytes of the CRC checking
        *  \param rCRC reference that returns the calculated CRC
        */

        void CalculateCRC(byte_t firtByteIndex
        										, byte_t numBytes
        										, word16_t & rCRC);

//@}
        
};



/*!
 * \class  CPackListHandler  PackMemManager.h " PackMemManager.h"
 * \author Oscar Rodriguez Polo
 * \brief class that implements the Nanosat1B Package List Handler
*/


class CPackListHandler{

	word16_t NodeListHeadIndex0,NodeListTailIndex0,PackCounter0;
	word16_t NodeListHeadIndex1,NodeListTailIndex1,PackCounter1;
	word16_t NodeListHeadIndex2,NodeListTailIndex2,PackCounter2;
	
	word16_t NodeListCurrentEditIndex, NodeListCurrentReadIndex;
    
	friend class  PackPool;

protected:

//*******************************************************
    //Head and Tail Management

	/*!
    *  \brief GetHead
    */
    inline void GetHead(word16_t &_NodeListHeadIndex0
    							, word16_t &_NodeListHeadIndex1
    							, word16_t &_NodeListHeadIndex2);

    /*!
    *  \brief Set Head, put current To Head
    */
    inline void SetHead(word16_t _NodeListHeadIndex0
    							, word16_t _NodeListHeadIndex1
    							, word16_t _NodeListHeadIndex2);

    /*!
    *  \brief Set Tail
    */
    inline void GetTail(word16_t &_NodeListTailIndex0
    							, word16_t &_NodeListTailIndex1
    							, word16_t &_NodeListTailIndex2);

    /*!
    *  \Set Tail
    */
    inline void SetTail(word16_t _NodeListTailIndex0
    							, word16_t _NodeListTailIndex1
    							, word16_t _NodeListTailIndex2);


    //!Add to Tail 

    void AddToTail(word16_t _NodeListTailIndex0
    							, word16_t _NodeListTailIndex1
    							, word16_t _NodeListTailIndex2);

 	//!Update To Next Node in List
    void UpdateToNext(word16_t &_NodeListIndex0
    									, word16_t &_NodeListIndex1
    									, word16_t &_NodeListIndex2);
    

    /*!
    *  \Check head MEM integrity 
    */

    bool_t CheckHeadMEM();


    /*!
    *  \Check Tail MEM integrity 
    */

    bool_t CheckTailMEM();

//*******************************************************


//*******************************************************
    //PackCounter

 //! Set PackCounter
    inline void SetPackCounter(word16_t packCount);



//*******************************************************
    //Pack List Static Control

 	inline bool_t IsLastEdit();

    inline bool_t IsLastRead();

//*******************************************************

public:

//*******************************************************
    //Constructor Init as an empty List

    //!Constructor, Init as an empty List
    CPackListHandler();

    

    /*!
    *  \brief Init as Empty Pack List Handler 
    */
    void InitAsEmptyPackList();

//*******************************************************


//*******************************************************
    //Word16 Access Control

        /* \brief read a word16 from current read pack. The index of the word in
         * current pack
         * \param wordIndex word16 index
         * \param wordValue var where the ridden word is copied  
         * \return false if current is not a valid package
         * 
         */
    bool_t ReadWord16(byte_t wordIndex
    										, word16_t &_wordValue) const ;

        /* \brief Write a word16 from current edit pack. The index of the word in
         * current pack
         * \param wordIndex word16 index
         * \param wordValue value to write
         * \return false if current is not a valid package
         * 
         */

    bool_t WriteWord16(byte_t wordIndex, word16_t _wordValue);

        //!return false if current is not a valid package
    /*!
    //  (_fistWord + _WordsCounter) <128, does not read extra words
    */
    bool_t ReadWord16Num(byte_t _firstWord, word16_t *_wordValues
    									, byte_t _WordsCounter) const ;

        //!return false if current is not a valid package
    /*!
    //  (_fistWord + _WordsCounter) <128, does not write extra words
    */
    bool_t WriteWord16Num(byte_t _firstWord
    									, const word16_t *_wordValues
    									, byte_t _WordsCounter);


//*******************************************************


//*******************************************************
    //Byte Access Control, distinguish between Little endian and big endian

    //! ReadByte
            /*!return false if it is not a valid package
            */
    bool_t  ReadByte(byte_t _numByte, byte_t &_byteValue) const ;

    //! WriteByte
            /*!return false if it is not a valid package
            */
    bool_t  WriteByte(byte_t _numByte, byte_t _byteValue);

//*******************************************************


//*******************************************************
    //Pack list dynamic control

    //!Add Pack in the Tail

    /*!
        *Return false if there is a MEMORY ERROR
        *If the pack is not valid, it is not added, 
        * but this is not a MEMORY ERROR
    */

    bool_t AddPack(CPackHandler &packHandler);

    //!Take One Pack from the Head

    /*!
            *Return false if there is a MEMORY ERROR
            *If it is Empty the pack will not be valid, 
            * but this is not a MEMORY ERROR
    */
    bool_t TakeOnePack(CPackHandler & _packHandler);


    //!Extract packages form the current list and Move 
    //them to the _packListDestiny

    /*!
            // _PackAcks marks the packages to extract. Max 32 packages.
            // The _PackAcks[0] bit is the mark for the first pack
             * , _PackAcks[1] for the second...
            // _PacksNumber set the number of packages to compute. 
             * Max 32 packages.
            // _PacksNumber return the number of packages extracted. 
             * Max 32 packages.

            // Return false if there is a MEMORY ERROR


    */
    bool_t ExtractPackages(word32_t _PackAcks, byte_t &_PacksNumber
    								, CPackListHandler & _packListDestiny);



    //!Extract packages form the current list and 
    //Move them to the _packListDestiny


    /*!
            // _PacksNumber set the number of packages to extract.
            // _PacksNumber return the number of packages extracted.

            // Return false if there is a MEMORY ERROR


    */
    bool_t ExtractPackages(word16_t &_PacksNumber
    								, CPackListHandler & _packListDestiny);


    
    //!Extract All packages form the current list and Move them 
    //to the packListDestiny
    bool_t ExtractAllPackages(CPackListHandler & packListDestiny);

    //!Is Empty
    bool_t IsEmpty();

    //! Get PackCounter
    word16_t GetPackCounter();

   
	//! Check PackCounter
    word16_t CheckPackCounter();
    
	
//*******************************************************




//*******************************************************
    //Pack List Static Control

            //!CurrentEdit and CurrentRead to head
    void ToHeadPack();

            //!Advance current
            /*!
            //  Return false if there is not next package and 
             * return to the first one
            */
    bool_t NextEditPack();

            /*!
            //!  Return false if there is not next package and return 
             * to the first one
            */
    bool_t NextReadPack();


		/**  \brief Get current Edit Pack 
	    * 	 \param reference of a packHandler where the current edit pack info
	    * 	is copied 
	    * 
	    */
    void GetCurrentEditPack(CPackHandler & pack)const;
    


		/**  \brief Get current Read Pack 
	    * 	 \param reference of a packHandler where the current read pack info
	    * 	is copied 
	    * 
	    */
    void GetCurrentReadPack(CPackHandler & pack)const;


            //!  Get currentEdit Pack and Advance CurrentEdit without 
            //Check if it is the last or if CurrentEdit is equal to ReadEdit
            /*!
            //  It is used in IRQ Handlers for fast access.
            */
    void GetEditPackAndAdvance(word16_t *& );

            //!  Get currentRead Pack and Advance CurrentRead without 
            //Check if it is the last or if CurrentEdit is equal to ReadEdit
             /*!
            //  It is used in IRQ Handlers for fast access.
            */
    void GetReadPackAndAdvance(word16_t *& );

   
    //*******************************************************



    //*******************************************************
        //!CheckCRC

    /*!
    //return 1 if CRC check of the packet is OK and false if not
    */

    byte_t CheckCRCCurrentReadPack();

    //*******************************************************

    //*******************************************************

    //!WriteCRC in CurrentEditPack

    /*!
    // _numBytes of CRC calculated from _firtByte and Write 
     * in _firstByte+_numBytes position
    */

    void WriteCRCCurrentEditPack(byte_t _firstByte
    											, byte_t _numBytes);

    //*******************************************************

};

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//********************************************************
//*****         PackPool
//********************************************************
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++


class PackPool{

        word16_t FreePackNodeListHead0,FreePackNodeListHead1
        												,FreePackNodeListHead2;
        word16_t FreePackNodeListTail0,FreePackNodeListTail1
        												,FreePackNodeListTail2;

public:

        //*******************************************************
        //General Management

            //!Init Packages Memory Manager
        void InitPackagesMemory();

            //!Check Integrity
        bool_t CheckPackagesMemory();

            //!Is Empty
        bool_t IsEmpty();

        //*******************************************************


        //*******************************************************
        //Pack List Management

            //******************************************************
                //!FreePackages:          Free a list of Packages,

            /**
                *\return false when the Memory pack system is wrong

                *In-Out
                    *\param listHandler

                *If Pool is empty do nothing
            */
        bool_t FreePackages(CPackListHandler & listHandler);



            //******************************************************
                //!AllocPackages:        Alloc a list of Packages,
            /**
                *\return false when the Memory pack system is wrong

                *param In-Out
                    *\param _numPackages
                        *In pack number required
                        *Out pack number allocated
            */
        bool_t AllocPackages(word16_t &_numPackages
        									, CPackListHandler & listHandler);


        //*******************************************************


#ifdef  EMULATION_FOR_TEST

        //!return NumPacksFree
        bool_t NumPacksFree(word16_t &numPacksFree);

        //*******************************************************
        //!One Pack Management

        bool_t FreeOnePackage(CPackHandler & _packHandler);
        bool_t AllocOnePackage(CPackHandler & _packHandler);


#endif
        //*******************************************************


};



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//********************************************************************
//      CHECK MEM
//********************************************************************
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


//*******************************************************************
//CheckMEM  and correct

//static bool_t CheckMEMWord16(word16_t *,word16_t *
//													,word16_t * );
bool_t CheckMEMWord16(word16_t *,word16_t *
													,word16_t * );


//********************************************************************
//GetMEMWord16 from redundant pointers

//static bool_t GetMEMWord16(word16_t & dataWord16
//													, word16_t *&
//													, word16_t *&
//													, word16_t * &);
bool_t GetMEMWord16(word16_t & dataWord16
													, word16_t *&
													, word16_t *&
													, word16_t * &);



void PacketsToBytes(CPackListHandler packets, byte_t * pBytes,uint8_t nf);







#endif
